package com.yhcui.monitor.logic;

import com.yhcui.monitor.bean.MonitorMsg;
import com.yhcui.monitor.bean.OsInfo;
import com.yhcui.monitor.bean.Result;
import com.yhcui.monitor.sender.DingDingSender;
import com.yhcui.monitor.utils.Const;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class OsInfoLogic {
    private static final Cache<String, OsInfo> cache = Caffeine.newBuilder()
            .maximumSize(100)
            .build();

    private static final String OS_CACHE_KEY_PRE = "osinfo:%s";

    @Value("${monitor.rule.memUsedPercent:80}")
    private Double memUsedPercent;

    @Value("${monitor.rule.cupUsedPercent:80}")
    private Double cupUsedPercent;

    @Value("${monitor.rule.diskUsedPercent:80}")
    private Double diskUsedPercent;

    @Value("${monitor.rule.swapUsedPercent:20}")
    private Double swapUsedPercent;

    @Value("${monitor.rule.cpuLoad:80}")
    private Double cpuLoad;

    @Autowired
    private DingDingSender dingDingSender;

    private static final Cache<String, Boolean> sendCache = Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(100)
            .build();

    private static final String SEND_KEY ="osInfo:send:%S";

    private static final String OS_MSG_TEM = "机器性能%s出现峰值，请及时进行验证。信息:%s";

    public Result analysisOsInfo(OsInfo osInfo) {

        String key = String.format(OS_CACHE_KEY_PRE, osInfo.getIp());
        cache.put(key, osInfo);
        if (isNeedMonitor(osInfo)) {
            String msg = String.format(OS_MSG_TEM, osInfo.getIp(), osInfo);
            log.error("OsInfoLogic sendMonitor analysisOsInfo:{}", msg);
            sendMsg(osInfo);

        }
        return Result.success();
    }

    public Result analysisCpuInfo(OsInfo osInfo) {
        boolean needMonitor =  osInfo.getCpuUsedPercent() > cupUsedPercent;
        if (needMonitor) {
            log.error("OsInfoLogic sendMonitor analysisCpuInfo:{}", osInfo.getCpuUsedPercent());
            sendMsg(osInfo);
        }
        return Result.success();
    }


    /**
     * 真实发送
     * */
    public  void sendMsg(OsInfo osInfo) {
        String key = String.format(SEND_KEY, osInfo.getIp());
        Boolean flag = sendCache.getIfPresent(key);

        if (flag != null && flag) {
            log.info("sendMsg flag is true.:{}",osInfo);
            return ;
        }
        log.error("OsInfoLogic sendMonitor sendMsg,用来统计自测的");
        String msg = String.format(OS_MSG_TEM, osInfo.getIp(), osInfo);
        MonitorMsg monitorMsg = MonitorMsg.builder()
                .atAll(false)
                .mobiles(Arrays.asList(new String[]{Const.Monitor_MOBILE}))
                .msg(msg).build();
        dingDingSender.sendMsg(monitorMsg);
        sendCache.put(key, true);
    }

    private boolean isNeedMonitor(OsInfo osInfo) {

        boolean needMonitor = (osInfo.getMemUsedPercent() >= memUsedPercent
                || osInfo.getDiskUsedPercent() >= diskUsedPercent
                || osInfo.getLoad1() > cpuLoad *  osInfo.getNumCPU());
        if (needMonitor) {
            return needMonitor;
        }
        if ( osInfo.getSwapTotal() == 0) {
            return false;
        }
        Double osInfoswapUsedPercent = ( osInfo.getSwapTotal() - osInfo.getSwapFree()) / (osInfo.getSwapTotal() * 1D);
        return osInfoswapUsedPercent >=  swapUsedPercent ;
    }
    public List<OsInfo> queryOsInfo(String ip) {
        List<OsInfo> osInfoList = new ArrayList<>();
        if (ip != null && ip.trim().length() != 0) {
            String key = String.format(OS_CACHE_KEY_PRE, ip);
            OsInfo osInfo = cache.getIfPresent(key);
            osInfoList.add(osInfo);
        } else {
            ConcurrentMap<String, OsInfo> map = cache.asMap();
            map.forEach(
                    (key, value) ->{
                        osInfoList.add(value);
                    }
            );
        }

        return osInfoList;
    }
}
